#include "LPC11xx.h"
#include "gpio.h"
#include "timer.h"
#include "adc.h"
#include "ssp.h"
#include "uart.h"
#include "halrfi.h"
#include "math.h"

/***************************************************************
 * Macro definitions                                           *
 ***************************************************************/
#define us2TimerInterval(us) ( us * (SystemAHBFrequency / 1000000) )
#define ms2TimerInterval(ms) ( ms * (SystemAHBFrequency / 1000) )

#define TIMER_DELAY     TIMER32[0]
#define TIMER_EVENT     TIMER16[0]
#define TIMER_PWM       TIMER32[1]

// fixed us time to let the real ADC_TIME = 2 * DAC_TIME
#define ADC_TIME    125
#define DAC_TIME    62

#define RECV_MODE 1
#define SEND_MODE 0

#define PACKET_LENGTH   64

/***************************************************************
 * Globol variables                                            *
 ***************************************************************/

extern volatile uint32_t ADCValue[ADC_NUM];
extern volatile uint32_t ADCIntDone;

extern volatile uint8_t  UARTBuffer[BUFSIZE];
extern volatile uint32_t UARTCount;

static uint32_t preVoiceData = 0;
static uint32_t curVoiceData = 0;

/*
 * one more packet space as a buffer, use PosRef to differentiate.
 */
static uint8_t  sendPkt[PACKET_LENGTH*2];
static uint32_t curSendPktPos = 0;
static uint32_t sendPktPosRef = 0;
static uint32_t sendBufPosRef = PACKET_LENGTH;
static uint32_t pktSwitched = 0;

static uint8_t  recvPkt[PACKET_LENGTH*2];
// at first, the receive packet contains no data, must wait buffer full.
static uint32_t curRecvPktPos = PACKET_LENGTH;
static uint32_t recvPktPosRef = PACKET_LENGTH;
static uint32_t curRecvBufPos = 0;
static uint32_t recvBufPosRef = 0;

static uint32_t currentMode = 2;        // not both mode at first.

//static uint8_t theSine[60] = {
//140,
//153,
//166,
//179,
//190,
//202,
//212,
//221,
//230,
//237,
//243,
//248,
//251,
//253,
//254,
//253,
//251,
//248,
//243,
//237,
//230,
//221,
//212,
//202,
//191,
//179,
//166,
//153,
//140,
//127,
//114,
//101,
//88,
//75,
//64,
//52,
//42,
//33,
//24,
//17,
//11,
//6,
//3,
//1,
//0,
//1,
//3,
//6,
//11,
//17,
//24,
//33,
//42,
//52,
//63,
//75,
//88,
//101,
//114,
//127
//};

/***************************************************************
 * Globol functions                                            *
 ***************************************************************/
extern void delayus(uint32_t us)
{
    TimerDelayUs(TIMER_DELAY, us);
}

/***************************************************************
 * Functions                                                   *
 ***************************************************************/
 
void initAD5660(void)
{
    uint8_t data[3] = {0, 0, 0};
    data[0] = 0x03;     // tree-state mode.
    
    // init spi.
    SSPInit(1, SSP_ClockPolarity_Low, SSP_ClockPhase_FallingEdge);
    
    // set power down mode.
    SSPSelect(1);
    SSPDeselect(1);
    SSPSelect(1);
    SSPSend(1, data, 3);
    SSPDeselect(1);
}

void writeAD5660(uint32_t digitValue, uint32_t Vrefdata)
{
    static const uint32_t vpp = 1*0xffff/5;        // 1V
    static const uint32_t offset = 0;           // input have offset already.
    uint8_t data[3] = {0, 0, 0};
//    
//    if (bitLength > 16) {
//        return;
//    }
    
    digitValue = digitValue * vpp / Vrefdata + offset;
    
    data[0] = 0x00;     // normal operation.
    data[1] = ( (digitValue >> 8) & 0xff );
    data[2] = ( digitValue & 0xff);
    
    SSPSelect(1);
    SSPDeselect(1);
    SSPSelect(1);
    SSPSend(1, data, 3);
    SSPDeselect(1);
}

void initLed(void)
{
    uint32_t i;
    for (i = 4; i < 12; ++i) {
        GPIOSetDir(PORT2, i, GPIO_DIR_OUTPUT);
    }
}

void setLed(uint32_t data)
{
    uint32_t i;
    for (i = 4; i < 12; ++i) {
        GPIOSetValue(PORT2, i, (data >> (11 - i)) & 0x1);
    } 
}

void initKey(void)
{
    uint32_t i;
    
    GPIOSetDir(PORT1, 9, GPIO_DIR_OUTPUT);
    
    for (i = 10; i < 12; ++i) {
        GPIOSetDir(PORT1, i, GPIO_DIR_INPUT);
    }
    for (i = 0; i < 6; ++i) {
        GPIOSetDir(PORT3, i, GPIO_DIR_INPUT);
    }
}

uint32_t getKey( void )
{
    uint32_t i;
    uint32_t data = 0;
    
    // set KEY_GND;
    GPIOSetValue(1, 9, 0);
    
    for (i = 10; i < 12; ++i) {
        data += GPIOGetValue(PORT1, i);
        data <<= 1;
    }
    for (i = 0; i < 6; ++i) {
        data += GPIOGetValue(PORT3, i);
        data <<= 1;
    }
    
    // kill the last shift.
    data >>= 1;
    
    // remove KEY_GND;
    GPIOSetValue(1, 9, 1);
    
    return data;
}

void dacNeedWrite(void *unuse)
{
    static uint32_t realDataTime = 2;

    ADCIntDone = 0;
    
    if (--realDataTime == 0) {
        realDataTime = 2;
        
        // need to wait for an new packet.
        if (curRecvPktPos == PACKET_LENGTH) {
            if (curRecvBufPos == PACKET_LENGTH) {
                // switch buffer.
                uint32_t tmp;
                tmp = recvPktPosRef;
                recvPktPosRef = recvBufPosRef;
                recvBufPosRef = tmp;
                
                curRecvPktPos = 2;      // ignore the packet header and led data.
                curRecvBufPos = 0;
                
                // the LED data is at the front of a buffer (except Pkt Header).
                setLed(recvPkt[recvPktPosRef + curRecvPktPos++]);
            }
            else {
                // if buffer not ready, give up and return.
                return;
            }
        }
        
        preVoiceData = curVoiceData;
        curVoiceData = recvPkt[recvPktPosRef + curRecvPktPos++];
        
        // write virtual data.
        writeAD5660((preVoiceData + curVoiceData) / 2, 0xff);
    }
    else {
        // write last real data.
        writeAD5660(curVoiceData, 0xff);
    }
    
    return;
}

void adcNeedRead(void *unuse)
{
    if (curSendPktPos == PACKET_LENGTH) {
        // switch buffer.
        uint32_t tmp;
        tmp = sendPktPosRef;
        sendPktPosRef = sendBufPosRef;
        sendBufPosRef = tmp;
        
        curSendPktPos = 0;
        
        pktSwitched = 1;
        
        sendPkt[sendPktPosRef + curSendPktPos++] = 0xff;
        sendPkt[sendPktPosRef + curSendPktPos++] = 0x00;
        sendPkt[sendPktPosRef + curSendPktPos++] = getKey();
    }
    
    sendPkt[sendPktPosRef + curSendPktPos++] = ADCRead(1) & 0xff;
//    sendPkt[sendPktPosRef + curSendPktPos++] = (uint8_t)( 0x7f * sin( (double)(curSendPktPos%20) * 6.28 / 20 ) + 0x7f );
//    sendPkt[sendPktPosRef + curSendPktPos++] = theSine[curSendPktPos%60];
    
    return;
}

void dataCome( void* unuse )
{
    if (curRecvBufPos < PACKET_LENGTH) {
        // judge the header.
        if (curRecvBufPos < 2) {
            curRecvBufPos += halrfiReceive(recvPkt + recvBufPosRef + curRecvBufPos);
            // headr place full, need judge.
            if (curRecvBufPos == 1) {
                // not header.
                if (recvPkt[recvBufPosRef + 0] != 0xff) {
                    // empty buffer.
                    curRecvBufPos = 0;
                    return;
                }
            }
            else if (curRecvBufPos == 2) {
                // not header.
                if ( (recvPkt[recvBufPosRef + 0] != 0xff) || (recvPkt[recvBufPosRef + 1] != 0x00) ) {
                    // empty buffer.
                    curRecvBufPos = 0;
                    return;
                }
            }
        }
        // not header, strore it.
        else {
            curRecvBufPos += halrfiReceive(recvPkt + recvBufPosRef + curRecvBufPos);
        }
    }
}

/***************************************************************
 * MAIN                                                        *
 ***************************************************************/
int main (void)
{
    SystemInit();             /* MUST BE INCLUDED! */

    GPIOInit();
    GPIOSetDir(PORT2, 7, GPIO_DIR_OUTPUT);

    // for delay
    TimerInit(TIMER_DELAY);
    
    TimerInit(TIMER_EVENT);
    TimerDisable(TIMER_EVENT);
    
    TimerInitPWM(TIMER_PWM, us2TimerInterval(DAC_TIME), MATCH1);
    TimerSetMatchPWM(TIMER_PWM, 0, us2TimerInterval(DAC_TIME)/2);
    TimerEnable(TIMER_PWM);
    
    ADCInit(ADC_CLK, 8);
    
    initAD5660();
    initLed();
    initKey();
    
    halrfiInit();
    halrfiSetIntCallback(dataCome);

    while (1) {
        // the mode has changed.
        if (currentMode != GPIOGetValue(1, 1)) {
            currentMode = GPIOGetValue(1, 1);
            // if is receive mode.
            if (currentMode == RECV_MODE) {
                TimerSetIntCallback(TIMER_EVENT, dacNeedWrite);
                TimerSetTime(TIMER_EVENT, us2TimerInterval(DAC_TIME));
                TimerEnable(TIMER_EVENT);
                halrfiRxOn();
            }
            // or send mode.
            else {
                TimerSetIntCallback(TIMER_EVENT, adcNeedRead);
                TimerSetTime(TIMER_EVENT, us2TimerInterval(ADC_TIME));
                TimerEnable(TIMER_EVENT);
                halrfiTxOn();
            }
        }
        // mode no change and the state is sending.
        else if (currentMode == SEND_MODE) {
            if (pktSwitched) {
                pktSwitched = 0;
                halrfiSend(sendPkt + sendBufPosRef, PACKET_LENGTH);
            }
        }
    }
}

/***************************************************************
 * END OF FILE                                                 *
 ***************************************************************/
